﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Resources;
using System.Collections;
using System.Drawing;
using System.Runtime.InteropServices;
using ResourceEditor.Core.ResourceDataObjects;

namespace ResourceEditor.Core
{
    public class ResourceFile
    {
        #region Properties
        internal FileInfo File { get; private set; }
        
        public string Name
        {
            get
            {
                return File.Name;
            }
        }
        
        private Dictionary<ResourceType, ResourceData> Data { get; set; }

        public ResourceDataString Strings
        {
            get
            {
                return (ResourceDataString)Data[ResourceType.String];
            }
        }

        public ResourceDataBitmap Bitmaps
        {
            get
            {
                return (ResourceDataBitmap)Data[ResourceType.Bitmap];
            }
        }

        public ResourceDataIcon Icons
        {
            get
            {
                return (ResourceDataIcon)Data[ResourceType.Icon];
            }
        }

        public ResourceDataAudio Audio
        {
            get
            {
                return (ResourceDataAudio)Data[ResourceType.Audio];
            }
        }

        public ResourceDataFile Files
        {
            get
            {
                return (ResourceDataFile)Data[ResourceType.File];
            }
        }

        public ResourceData<object> Others
        {
            get
            {
                return (ResourceData<object>)Data[ResourceType.Other];
            }
        }

        internal bool HasChanges
        {
            get
            {
                return Data.Values.Any(item => item.HasChanges);
            }
        }
        #endregion

        #region Ctor
        public ResourceFile(FileInfo file)
        {
            File = file;
            CreateData();

            using (ResourceReader reader = new ResourceReader(file.OpenRead()))
            {
                foreach (DictionaryEntry item in reader)
                {
                   DecideWhereInsertItem(item);
                }
            }

            foreach (var item in Data)
            {
                item.Value.SortByKey();
            }
        }
        
        #endregion

        #region Methods
        private void CreateData()
        {
            Data = new Dictionary<ResourceType, ResourceData>();

            Data.Add(ResourceType.Audio, new ResourceDataAudio(this));
            Data.Add(ResourceType.Bitmap, new ResourceDataBitmap(this));
            Data.Add(ResourceType.File, new ResourceDataFile(this));
            Data.Add(ResourceType.Icon, new ResourceDataIcon(this));
            Data.Add(ResourceType.Other, new ResourceData<object>(this));
            Data.Add(ResourceType.String, new ResourceDataString(this));

        }

        private void DecideWhereInsertItem(DictionaryEntry item)
        {
            string stringValue = item.Value as string;
            if (stringValue != null)
            {
                Strings.AddFromFile(item.Key.ToString(), stringValue);
                return;
            }

            Image imageValue = item.Value as Image;
            if (imageValue != null)
            {
                Bitmaps.AddFromFile(item.Key.ToString(), imageValue);
                return;
            }

            Icon iconValue = item.Value as Icon;
            if (iconValue != null)
            {
                Icons.AddFromFile(item.Key.ToString(), iconValue);
                return;
            }

            UnmanagedMemoryStream audioValue = item.Value as UnmanagedMemoryStream;
            if (audioValue != null)
            {
                Audio.AddFromFile(item.Key.ToString(), audioValue);
                return;
            }

            byte[] fileValue = item.Value as byte[];
            if (fileValue != null)
            {
                Files.AddFromFile(item.Key.ToString(), fileValue);
                return;
            }

            Others.AddFromFile(item.Key.ToString(), item.Value);
        }


        public bool IsKeyExist(string key)
        {
            return Data.Values.Any(item => item.IsKeyExist(key));
        }

        #region Save
        internal void SaveEmbedded()
        {
            try
            {
                using (IResourceWriter writer = new ResourceWriter(File.FullName))
                {
                    WriteResources(writer);
                }
            }
            catch (Exception ex)
            {
                Logger.Exception(ex);
                throw;
            }
        }

        internal void SaveResx()
        {
            try
            {
                string[] dots = File.Name.Split('.');
                string name = dots[dots.Length - 2];
                name += ".resx";

                using (IResourceWriter writer = new ResXResourceWriter(Path.Combine(File.Directory.FullName, name)))
                {
                    WriteResources(writer);
                }
            }
            catch (Exception ex)
            {
                Logger.Exception(ex);
                throw;
            }
        }

        private void WriteResources(IResourceWriter writer)
        {
            WriteStrings(writer);
            WriteBitmaps(writer);
            WriteAudio(writer);
            WriteFiles(writer);
            WriteIcons(writer);
            WriteOthers(writer);
        }

        private void WriteOthers(IResourceWriter writer)
        {
            foreach (var item in Others)
            {
                if (item.State != ItemState.Deleted)
                {
                    writer.AddResource(item.Key, item.Current);
                }
            }
        }

        private void WriteIcons(IResourceWriter writer)
        {
            foreach (var item in Icons)
            {
                if (item.State != ItemState.Deleted)
                {
                    writer.AddResource(item.Key, item.Current);
                }
            }
        }

        private void WriteFiles(IResourceWriter writer)
        {
            foreach (var item in Files)
            {
                if (item.State != ItemState.Deleted)
                {
                    writer.AddResource(item.Key, item.Current);
                }
            }
        }

        private void WriteAudio(IResourceWriter writer)
        {
            foreach (var item in Audio)
            {
                if (item.State != ItemState.Deleted)
                {
                    byte[] buffer = new byte[item.Current.Length];
                    item.Current.Position = 0;
                    item.Current.Read(buffer, 0, buffer.Length);
                    MemoryStream ms = new MemoryStream(buffer);
                    writer.AddResource(item.Key, ms);
                }
            }
        }

        private void WriteBitmaps(IResourceWriter writer)
        {
            foreach (var item in Bitmaps)
            {
                if (item.State != ItemState.Deleted)
                {
                    writer.AddResource(item.Key, item.Current);
                }
            }
        }

        private void WriteStrings(IResourceWriter writer)
        {
            foreach (var item in Strings)
            {
                if (item.State !=  ItemState.Deleted)
                {
                    writer.AddResource(item.Key, item.Current);
                }
            }
        }
        #endregion

        #endregion
    }
}
